package va;

import global.Convert;
import global.PageId;
import global.RID;
import global.Vector100Dtype;

import java.io.IOException;
import java.nio.ByteBuffer;

import va_file.VAFile;

public class VAEntry {
	
	public BitSet approximation;
	public RID rid;
	
	// Object that holds the approximation value for a vector
	
	public VAEntry(BitSet approximation, RID rid) {
		this.approximation = approximation;
		this.rid = rid;
	}
	
	// Formats the VAEntry into a string to display
	
	public String toString() {
		String returnValue = "Approximation: " + this.approximation.toString() + "\n";
		returnValue += "Row ID: " + this.rid.toString() + "\n";
		return returnValue;
	}
	
	// Takes a byte array and creates the corresponding VAEntry object
	
	public static VAEntry fromBytes(byte[] bytes) throws IOException {
		int length = bytes.length;
		ByteBuffer buffer = ByteBuffer.wrap(bytes);
		
		byte[] slotNoBytes = new byte[4];
		buffer.get(slotNoBytes, 0, 4);
		
		byte[] pageIdBytes = new byte[4];
		buffer.get(pageIdBytes, 0, 4);
		
		byte[] approximationBytes = new byte[length-8];
		buffer.get(approximationBytes, 0, (length-8));
		
		BitSet approximation = BitSet.valueOf(approximationBytes);
		int slotNo = Convert.getIntValue(0, slotNoBytes);
		int pid = Convert.getIntValue(0, pageIdBytes);
		
		PageId pageId = new PageId(pid);
		RID rid = new RID(pageId, slotNo);
		
		return new VAEntry(approximation, rid);
	}
	
	// Takes a VAEntry object and converts it into a byte array to insert into the database
	
	public byte[] toBytes() throws IOException {
		byte[] approxByteArray = this.approximation.toByteArray();
		byte[] record = new byte[8 + approxByteArray.length];
		byte[] ridBytes = new byte[8];
		this.rid.writeToByteArray(ridBytes, 0);
		
		
		ByteBuffer target = ByteBuffer.wrap(record);
		target.put(ridBytes);
		target.put(approxByteArray);
		
		return target.array();
	}
	
	/*
	 * Creates a BitSet approximation for a given set of ranges, vector, and bits per dimension
	 */
	public static BitSet CreateApproximation(Vector100Dtype vector, Range[] ranges, int bitsPerDimension) {
		BitSet approximation = new BitSet(bitsPerDimension * 100);
		int currentApproxIndex = 0;
		for (int i = 0; i < 100; i++) {
			int value = (int) vector.getIndex(i);
			int rangeIndex = Range.FindRangeIndex(ranges, value);
			BitSet bitValue = BitSet.FromInt(rangeIndex, bitsPerDimension);
			for (int n = 0; n < bitsPerDimension; n++) {
				approximation.set(currentApproxIndex, bitValue.get(n));
				currentApproxIndex++;
			}
		}
		return approximation;
	}

    // Takes a string and converts it to a BitSet vector approximation

    public static BitSet CreateApproximationFromIndexString(String indexString, int bitsPerDimension) {
        BitSet result = new BitSet(100 * bitsPerDimension);
        int charsPerDimension = (int) Math.ceil(bitsPerDimension/4.0);
        int currentApproxIndex = 0;
        //Iterate through each dimension's approximation and store the bits in the bitset object bit
        for(int i = 0; i < 100 * charsPerDimension; i += charsPerDimension)
        {
            String subString = indexString.substring(i, i + charsPerDimension);
            int num = Integer.parseInt(subString, 16);
            BitSet subApprox = BitSet.FromInt(num, bitsPerDimension);
//            int offset = i * bitsPerDimension;
//            String subString = indexString.substring(offset, offset + bitsPerDimension);
//            BitSet subApprox = BitSet.FromIndexKey(subString);
            for (int j = 0; j < bitsPerDimension; j++) {
                result.set(currentApproxIndex, subApprox.get(j));
                currentApproxIndex++;
            }
        }

        return result;
    }

    // Takes a BitSet approximation and converts it to a string

    public static String GetApproximationString(BitSet approximation, int bitsPerDimension) {
        String result="";
        int charsPerDimension = (int) Math.ceil(bitsPerDimension/4.0);

        //Iterate through each dimension's approximation and store the bits in the bitset object bit
        for(int i = 0; i < 100; i++)
        {
            int offset = i * bitsPerDimension;
//            result += approximation.get(offset, offset + bitsPerDimension).toIndexString(bitsPerDimension);
            int approximationResult = approximation.get(offset, offset + bitsPerDimension).toInt(bitsPerDimension);
            String hex = Integer.toHexString(approximationResult);
            int j = hex.length();
            for (; j < charsPerDimension; j++) {
                hex = "0" + hex;
            }
            result += hex;
        }

        return result;
    }

}
